/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <gtk/gtk.h>
#include <stdarg.h>
#include <string.h>

//#define BE_NAME  "/tmp/gelogger.db"
const char* BE_NAME = NULL;
#define BE_VERSION 1

sqlite3* backend = NULL;
GtkWidget *window;

static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
  return FALSE;
}
 
static void destroy(GtkWidget *widget, gpointer data) {
  gtk_widget_destroy( window );
}
 
static void clicked(GtkWidget *widget, gpointer data) {
  gtk_widget_destroy( window );
  gtk_main_quit();
}


static void gtk_alert( const char * msg, ... )
{
 
  char lmsg[1024];
  va_list args;
  va_start (args, msg);
  vsnprintf( lmsg, 1023, msg, args );  
  va_end (args);

 
  GtkWidget *button;
  GtkWidget *label;
  GtkWidget *vbox;
   
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_container_set_border_width(GTK_CONTAINER(window), 10);
//  g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(delete_event), NULL);
//  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
   
  button = gtk_button_new_with_label("OK");
  g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clicked), NULL);
//  gtk_widget_show(button);
 
  label = gtk_label_new( lmsg );
  vbox = gtk_vbox_new( 0,5 );
  gtk_box_pack_start( GTK_BOX( vbox ), label, 0, 0, 5 );
  gtk_box_pack_start( GTK_BOX( vbox ), button, 0, 0, 5 );
    
 
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_window_set_position( GTK_WINDOW( window ), GTK_WIN_POS_CENTER );
 
  gtk_widget_show_all(window);
  gtk_main();

}

static int be_check_version()
{
    //try to do select version from "version" table, compare with BE_VERSION     
    
    sqlite3_stmt *stmt = NULL;
    const char* tail = NULL;
    int ret = 0;
    int version = 0;
    
    ret = sqlite3_prepare_v2( backend, "select version from version", -1, &stmt, &tail );

    if( stmt == NULL || ret != SQLITE_OK )
    {
        //may be database is not initialized at all, try to update
        return 0;    
    }
    //read one line
    ret = sqlite3_step(stmt);
    if( ! ( ret == SQLITE_ROW || ret == SQLITE_OK || ret == SQLITE_DONE ) )
    {
        //fatal, may be broken database
        gtk_alert( "Database may be broken, please remove %s and restart applet\n", BE_NAME );
        exit(1);    
    }
    
    version =  sqlite3_column_int( stmt, 0 );

    ret = sqlite3_finalize(stmt);

    if( version > BE_VERSION )
    {
        //fatal, database is not compatible
        gtk_alert( "fatal: database is in higher version as the applet requres!\n" );
        exit(1);
    }

    
    if( version != BE_VERSION )
    {
        return 0;
    }
    
    //version is OK
    return 1;
}

static void be_update( const char* stmt )
{
    char* errmsg = NULL;
    
    int ret = sqlite3_exec( backend, stmt, NULL, NULL, &errmsg );
    
    if( ret != SQLITE_OK )
    {
        if( errmsg != NULL )
        {   
            gtk_alert( errmsg );
            gtk_alert( "fatal: sql error: %s\n" );
            sqlite3_free( errmsg );
        }
        exit(1);
    } 
}
    
static void be_update_1()
{
    //intially create database    
    be_update( "create table version ( version number );" );
    be_update( " create table entries ( "
               "       dt          datetime not null, "
               "       message     text "
               " ); " );
               
    //finally do not forget to set version           
    be_update( "insert into version (version ) values ( 1 );" );
    
}

void be_set_database_name( const char* _logfile )
{
    BE_NAME = strdup( _logfile );
}

void be_open_database()
{
    if( SQLITE_OK != sqlite3_open( BE_NAME, &backend ) )
    {
        //TODO: replace message by an alert window
        gtk_alert( "could not open backend file %s\n", BE_NAME );    
        exit(1);
    }
    
    //check version
    if( !be_check_version() )
    {
        //do updates
        be_update_1();
//        be_update_2();
//        be_update_3();    
    }        
}

void be_close_database( )
{
    sqlite3_close( backend );    
}

void be_report( time_t time, const char* message )
{
//    gtk_alert( "[%s]", message );


   //try to do select version from "version" table, compare with BE_VERSION     
    be_open_database();
    
    sqlite3_stmt *stmt = NULL;
    const char* tail = NULL;
    int ret = 0;
    int version = 0;
    
    ret = sqlite3_prepare_v2( backend, "insert into entries ( dt, message ) values ( ?, ? );", -1, &stmt, &tail );

    if( stmt == NULL || ret != SQLITE_OK )
    {
        gtk_alert( "may be database is not initialized at all, try to update" );
        return;    
    }
    
    sqlite3_bind_int64( stmt, 1, time );
    sqlite3_bind_text ( stmt, 2, message, -1, SQLITE_STATIC );
    
    ret = sqlite3_step(stmt);
    ret = sqlite3_finalize( stmt );
    
    if( ! ( ret == SQLITE_DONE || ret == SQLITE_OK ) )
    {
        gtk_alert( "return code = %d [%s]", ret, sqlite3_errmsg( backend ) );
    }
    
    be_close_database();
    
}
